<!DOCTYPE HTML>
<html>

<head>
	<link rel="bookmark"  type="image/x-icon"  href="/img/logo_miccall.png"/>
	<link rel="shortcut icon" href="/img/logo_miccall.png">
	
			    <title>
    Ame雨
    </title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
    <link rel="stylesheet" href="/amelin-ting/css/mic_main.css" />
    <link rel="stylesheet" href="/amelin-ting/css/dropdownMenu.css" />
    <meta name="keywords" content="Ame雨" />
    
    	<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
	 
    <noscript>
        <link rel="stylesheet" href="/amelin-ting/css/noscript.css" />
    </noscript>
    <style type="text/css">
        body:before {
          content: ' ';
          position: fixed;
          top: 0;
          background: url('/amelin-ting/img/bg.jpg') center 0 no-repeat;
          right: 0;
          bottom: 0;
          left: 0;
          background-size: cover; 
        }
    </style>

			    
  
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
        }
      });
    </script>

    <script type="text/x-mathjax-config">
      MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for (i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
        }
      });
    </script>
    <script async type="text/javascript" src="//cdn.bootcss.com/mathjax/2.7.1/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
  


    <script src="/amelin-ting/js/jquery.min.js"></script>
    <script src="/amelin-ting/js/jquery.scrollex.min.js"></script>
    <script src="/amelin-ting/js/jquery.scrolly.min.js"></script>
    <script src="/amelin-ting/js/skel.min.js"></script>
    <script src="/amelin-ting/js/util.js"></script>
    <script src="/amelin-ting/js/main.js"></script>
	
<meta name="generator" content="Hexo 5.4.0"></head>
    
		
<!-- Layouts -->



<!--  代码渲染  -->
<link rel="stylesheet" href="/css/prism_coy.css" />
<link rel="stylesheet" href="/css/typo.css" />
<!-- 文章页 -->
<body class="is-loading">
    <!-- Wrapper 外包 s-->
    <div id="wrapper" class="fade-in">
        <!-- Intro 头部显示 s -->
        <!-- Intro 头部显示 e -->
        <!-- Header 头部logo start -->
        <header id="header">
    <a href="/amelin-ting/" class="logo">Art Space</a>
</header>
        <!-- Nav 导航条 start -->
        <nav id="nav" class="special" >
            <ul class="menu links" >
			<!-- Homepage  主页  --> 
			<li >
	            <a href="/amelin-ting/" rel="nofollow">主页</a>
	        </li>
			<!-- categories_name  分类   --> 
	        
	        <li class="active">
	            <a href="#s1">分类</a>
	                    <ul class="submenu">
	                        <li>
	                        <a class="category-link" href="/amelin-ting/categories/Go/">Go</a></li><li><a class="category-link" href="/amelin-ting/categories/django/">django</a></li><li><a class="category-link" href="/amelin-ting/categories/drf/">drf</a></li><li><a class="category-link" href="/amelin-ting/categories/gin/">gin</a></li><li><a class="category-link" href="/amelin-ting/categories/go/">go</a></li><li><a class="category-link" href="/amelin-ting/categories/linux/">linux</a></li><li><a class="category-link" href="/amelin-ting/categories/mysql/">mysql</a></li><li><a class="category-link" href="/amelin-ting/categories/python/">python</a></li><li><a class="category-link" href="/amelin-ting/categories/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/">内网穿透</a></li><li><a class="category-link" href="/amelin-ting/categories/%E5%89%8D%E7%AB%AF/">前端</a>
	                    </ul>
	        </li>
	        
	        <!-- archives  归档   --> 
	        
	        
		        <!-- Pages 自定义   -->
		        
		        <li>
		            <a href="/about/" title="简历">
		                简历
		            </a>
		        </li>
		        
		        <li>
		            <a href="/group/" title="团队">
		                团队
		            </a>
		        </li>
		        
		        <li>
		            <a href="/gallery/" title="图库">
		                图库
		            </a>
		        </li>
		        
		        <li>
		            <a href="/tag/" title="标签">
		                标签
		            </a>
		        </li>
		        


            </ul>
            <!-- icons 图标   -->
			<ul class="icons">
                    
                    <li>
                        <a title="github" href="https://github.com/miccall" target="_blank" rel="noopener">
                            <i class="icon fa fa-github"></i>
                        </a>
                    </li>
                    
                    <li>
                        <a title="500px" href="http://500px.com" target="_blank" rel="noopener">
                            <i class="icon fa fa-500px"></i>
                        </a>
                    </li>
                    
			</ul>
</nav>

        <div id="main" >
            <div class ="post_page_title_img" style="height: 25rem;background-image: url(https://img0.baidu.com/it/u=826859698,2565979176&amp;fm=26&amp;fmt=auto);background-position: center; background-repeat:no-repeat; background-size:cover;-moz-background-size:cover;overflow:hidden;" >
                <a href="#" style="padding: 4rem 4rem 2rem 4rem ;"><h2 >Go性能优化</h2></a>
            </div>
            <!-- Post -->
            <div class="typo" style="padding: 3rem;">
                <h2 id="一、Go性能优化"><a href="#一、Go性能优化" class="headerlink" title="一、Go性能优化"></a>一、Go性能优化</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在计算机性能调试领域中,profiling 是指对应用程序的画像。画像就是应用程序使用CPU和内存的情况。Go语言是一个对性能特别看重的语言，因此Go里面自带了profiling的库。</span></span><br><span class="line"></span><br><span class="line"><span class="number">1.</span> Go语言项目中的性能优化主要有以下几个方面</span><br><span class="line">    CPU profile: 报告程序的CPU使用情况，按照一定的频率去采集应用程序在CPU和寄存器上的数据</span><br><span class="line">    Memory Profile(Heap Profile): 报告程序的内存使用情况</span><br><span class="line">    Block Profiling：报告 goroutines 不在运行状态的情况，可以用来分析和查找死锁等性能瓶颈</span><br><span class="line">    Goroutine Profiling：报告 goroutines 的使用情况，有哪些 goroutine，它们的调用关系是怎样的</span><br><span class="line"></span><br><span class="line"><span class="number">2.</span> 采集性能数据</span><br><span class="line">    Go语言内置了获取程序的运行数据的工具，包括以下两个标准库</span><br><span class="line">        runtime/pprof:采集工具型应用运行数据进行分析</span><br><span class="line">        net/http/pprof:采集服务型应用运行时数据进行分析</span><br><span class="line">    pprof开启后，每隔一段时间(<span class="number">10</span>ms)就会收集当前的堆栈信息，获取各个函数占用的CPU以及内存资源；最后通过对这些采集数据进行分析，形成一个性能分析报告</span><br><span class="line">    <span class="comment">// 注意，我们只应该在性能测试的时候才在代码中引入pprof</span></span><br></pre></td></tr></table></figure>

<h2 id="二、工具型应用"><a href="#二、工具型应用" class="headerlink" title="二、工具型应用"></a>二、工具型应用</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 如果你的应用程序是运行一段时间就结束退出类型。那么最好的办法是在应用退出的时候把 profiling 的报告保存到文件中，进行分析。对于这种情况，可以使用runtime/pprof库。</span></span><br><span class="line"></span><br><span class="line"><span class="number">1.</span> CPU性能分析</span><br><span class="line">	开启CPU性能分析</span><br><span class="line">		pprof.StartCPUProfile(w io.Writer)</span><br><span class="line">	停止CPU性能分析</span><br><span class="line">		pprof.StopCPUProfile()</span><br><span class="line">	<span class="comment">// 应用执行结束后，就会生成一个新文件，保存了我们的CPU profiling数据。得到采样数据后，使用go tool pprof工具进行cpu性能分析</span></span><br><span class="line"></span><br><span class="line"><span class="number">2.</span> 内存性能优化</span><br><span class="line">	记录程序的堆栈信息</span><br><span class="line"></span><br><span class="line">    pprof.WriteHeapProfile(w io.Writer)</span><br><span class="line">    得到采样数据之后，使用<span class="keyword">go</span> tool pprof工具进行内存性能分析。</span><br><span class="line"></span><br><span class="line">    <span class="keyword">go</span> tool pprof默认是使用-inuse_space进行统计，还可以使用-inuse-objects查看分配对象的数量</span><br></pre></td></tr></table></figure>

<h2 id="三、服务型应用"><a href="#三、服务型应用" class="headerlink" title="三、服务型应用"></a>三、服务型应用</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">如果你的应用程序是一直运行的，比如 web 应用，那么可以使用net/http/pprof库，它能够在提供 HTTP 服务进行分析。</span><br><span class="line"></span><br><span class="line">如果使用了默认的http.DefaultServeMux（通常是代码直接使用 http.ListenAndServe(“<span class="number">0.0</span><span class="number">.0</span><span class="number">.0</span>:<span class="number">8000</span>”, <span class="literal">nil</span>)），只需要在你的web server端代码中按如下方式导入net/http/pprof</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> _ <span class="string">&quot;net/http/pprof&quot;</span></span><br><span class="line"></span><br><span class="line">如果你使用自定义的 Mux，则需要手动注册一些路由规则：</span><br><span class="line">r.HandleFunc(<span class="string">&quot;/debug/pprof/&quot;</span>, pprof.Index)</span><br><span class="line">r.HandleFunc(<span class="string">&quot;/debug/pprof/cmdline&quot;</span>, pprof.Cmdline)</span><br><span class="line">r.HandleFunc(<span class="string">&quot;/debug/pprof/profile&quot;</span>, pprof.Profile)</span><br><span class="line">r.HandleFunc(<span class="string">&quot;/debug/pprof/symbol&quot;</span>, pprof.Symbol)</span><br><span class="line">r.HandleFunc(<span class="string">&quot;/debug/pprof/trace&quot;</span>, pprof.Trace)</span><br><span class="line"></span><br><span class="line">如果你使用的是gin框架，那么推荐使用github.com/gin-contrib/pprof，在代码中通过以下命令注册pprof相关路由。</span><br><span class="line">pprof.Register(router)</span><br><span class="line">不管哪种方式，你的 HTTP 服务都会多出/debug/pprof endpoint</span><br><span class="line"></span><br><span class="line">这个路径下还有几个子页面：</span><br><span class="line"></span><br><span class="line">/debug/pprof/profile：访问这个链接会自动进行 CPU profiling，持续 <span class="number">30</span>s，并生成一个文件供下载</span><br><span class="line">/debug/pprof/heap： Memory Profiling 的路径，访问这个链接会得到一个内存 Profiling 结果的文件</span><br><span class="line">/debug/pprof/block：block Profiling 的路径</span><br><span class="line">/debug/pprof/goroutines：运行的 goroutines 列表，以及调用关系</span><br></pre></td></tr></table></figure>

<h2 id="四、go-tool-pprof命令"><a href="#四、go-tool-pprof命令" class="headerlink" title="四、go tool pprof命令"></a>四、go tool pprof命令</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">不管是工具型应用还是服务型应用，我们使用相应的pprof库获取数据之后，下一步的都要对这些数据进行分析，我们可以使用<span class="keyword">go</span> tool pprof命令行工具。</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> tool pprof最简单的使用方式为:</span><br><span class="line"><span class="keyword">go</span> tool pprof [binary] [source]</span><br><span class="line"></span><br><span class="line">其中：</span><br><span class="line">binary 是应用的二进制文件，用来解析各种符号；</span><br><span class="line">source 表示 profile 数据的来源，可以是本地的文件，也可以是 http 地址。</span><br><span class="line">注意事项： 获取的 Profiling 数据是动态的，要想获得有效的数据，请保证应用处于较大的负载（比如正在生成中运行的服务，或者通过其他工具模拟访问压力）。否则如果应用处于空闲状态，得到的结果可能没有任何意义。 </span><br><span class="line"></span><br><span class="line">通过flag我们可以在命令行控制是否开启CPU和Mem的性能分析。 将上面的代码保存并编译成runtime_pprof可执行文件，执行时加上-cpu命令行参数如下：</span><br><span class="line">./runtime_pprof -cpu</span><br><span class="line">等待<span class="number">20</span>秒后会在当前目录下生成一个cpu.pprof文件。</span><br></pre></td></tr></table></figure>

<h2 id="五、命令行交互页面"><a href="#五、命令行交互页面" class="headerlink" title="五、命令行交互页面"></a>五、命令行交互页面</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line">我们使用<span class="keyword">go</span>工具链里的pprof来分析一下。</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> tool pprof cpu.pprof</span><br><span class="line">执行上面的代码会进入交互界面如下：</span><br><span class="line"></span><br><span class="line">Type: cpu</span><br><span class="line">Time: Sep <span class="number">7</span>, <span class="number">2021</span> at <span class="number">6</span>:<span class="number">25</span>pm (CST)</span><br><span class="line">Duration: <span class="number">20.23</span>s, Total samples = <span class="number">101.22</span>s (<span class="number">500.30</span>%)</span><br><span class="line">Entering interactive mode (<span class="keyword">type</span> <span class="string">&quot;help&quot;</span> <span class="keyword">for</span> commands, <span class="string">&quot;o&quot;</span> <span class="keyword">for</span> options)</span><br><span class="line">(pprof)</span><br><span class="line">我们可以在交互界面输入top3来查看程序中占用CPU前<span class="number">3</span>位的函数：</span><br><span class="line"></span><br><span class="line">(pprof) top3</span><br><span class="line">Showing nodes accounting <span class="keyword">for</span> <span class="number">100.84</span>s, <span class="number">99.62</span>% of <span class="number">101.22</span>s total</span><br><span class="line">Dropped <span class="number">38</span> nodes (cum &lt;= <span class="number">0.51</span>s)</span><br><span class="line">      flat  flat%   sum%        cum   cum%</span><br><span class="line">    <span class="number">39.05</span>s <span class="number">38.58</span>% <span class="number">38.58</span>%     <span class="number">39.07</span>s <span class="number">38.60</span>%  runtime.chanrecv</span><br><span class="line">    <span class="number">34.44</span>s <span class="number">34.02</span>% <span class="number">72.60</span>%     <span class="number">73.54</span>s <span class="number">72.65</span>%  runtime.selectnbrecv</span><br><span class="line">    <span class="number">27.35</span>s <span class="number">27.02</span>% <span class="number">99.62</span>%    <span class="number">100.95</span>s <span class="number">99.73</span>%  main.logicCode</span><br><span class="line">其中：</span><br><span class="line"></span><br><span class="line">flat：当前函数占用CPU的耗时</span><br><span class="line">flat：:当前函数占用CPU的耗时百分比</span><br><span class="line">sun%：函数占用CPU的耗时累计百分比</span><br><span class="line">cum：当前函数加上调用当前函数的函数占用CPU的总耗时</span><br><span class="line">cum%：当前函数加上调用当前函数的函数占用CPU的总耗时百分比</span><br><span class="line">最后一列：函数名称</span><br><span class="line">在大多数的情况下，我们可以通过分析这五列得出一个应用程序的运行情况，并对程序进行优化。</span><br><span class="line"></span><br><span class="line">我们还可以使用list 函数名命令查看具体的函数分析，例如执行list logicCode查看我们编写的函数的详细分析。</span><br><span class="line"></span><br><span class="line">(pprof) list logicCode</span><br><span class="line">Total: <span class="number">101.22</span>s</span><br><span class="line">ROUTINE ======================== main.logicCode in D:\GoProject\src\day7\flag\flag.<span class="keyword">go</span>      </span><br><span class="line">    <span class="number">27.35</span>s    <span class="number">100.95</span>s (flat, cum) <span class="number">99.73</span>% of Total</span><br><span class="line">         .          .      <span class="number">8</span>:   <span class="string">&quot;runtime/pprof&quot;</span></span><br><span class="line">         .          .      <span class="number">9</span>:   <span class="string">&quot;time&quot;</span></span><br><span class="line">         .          .     <span class="number">10</span>:)</span><br><span class="line">         .          .     <span class="number">11</span>:</span><br><span class="line">         .          .     <span class="number">12</span>:<span class="comment">// 一段有问题的代码</span></span><br><span class="line">         .       <span class="number">20</span>ms     <span class="number">13</span>:<span class="function"><span class="keyword">func</span> <span class="title">logicCode</span><span class="params">()</span></span> &#123;</span><br><span class="line">         .          .     <span class="number">14</span>:   <span class="keyword">var</span> c <span class="keyword">chan</span> <span class="keyword">int</span></span><br><span class="line">         .          .     <span class="number">15</span>:   <span class="keyword">for</span> &#123;</span><br><span class="line">         .          .     <span class="number">16</span>:           <span class="keyword">select</span> &#123;</span><br><span class="line">    <span class="number">27.35</span>s    <span class="number">100.93</span>s     <span class="number">17</span>:           <span class="keyword">case</span> v := &lt;-c:</span><br><span class="line">         .          .     <span class="number">18</span>:                   fmt.Printf(<span class="string">&quot;recv from chan, value:%v\n&quot;</span>, v)</span><br><span class="line">         .          .     <span class="number">19</span>:           <span class="keyword">default</span>:</span><br><span class="line">         .          .     <span class="number">20</span>:           &#125;</span><br><span class="line">         .          .     <span class="number">21</span>:   &#125;</span><br><span class="line">         .          .     <span class="number">22</span>:&#125;</span><br><span class="line">(pprof) </span><br><span class="line">通过分析发现大部分CPU资源被<span class="number">17</span>行占用，我们分析出<span class="keyword">select</span>语句中的<span class="keyword">default</span>没有内容会导致上面的<span class="keyword">case</span> v:=&lt;-c:一直执行。我们在<span class="keyword">default</span>分支添加一行time.Sleep(time.Second)即可。</span><br></pre></td></tr></table></figure>

<h2 id="六、图形化"><a href="#六、图形化" class="headerlink" title="六、图形化"></a>六、图形化</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">或者可以直接输入web，通过svg图的方式查看程序中详细的CPU占用情况。 想要查看图形化的界面首先需要安装graphviz图形化工具。</span><br><span class="line"></span><br><span class="line">Mac：</span><br><span class="line">	brew install graphviz</span><br><span class="line">Windows: </span><br><span class="line">	下载graphviz 将graphviz安装目录下的bin文件夹添加到Path环境变量中。 在终端输入dot -version查看是否安装成功。</span><br><span class="line"></span><br><span class="line">关于图形的说明： 每个框代表一个函数，理论上框的越大表示占用的CPU资源越多。 方框之间的线条代表函数之间的调用关系。 线条上的数字表示函数调用的次数。 方框中的第一行数字表示当前函数占用CPU的百分比，第二行数字表示当前函数累计占用CPU的百分比。</span><br><span class="line"></span><br><span class="line">除了分析CPU性能数据，pprof也支持分析内存性能数据。比如，使用下面的命令分析http服务的heap性能数据，查看当前程序的内存占用以及热点内存对象使用的情况。</span><br><span class="line"></span><br><span class="line"># 查看内存占用数据</span><br><span class="line">    <span class="keyword">go</span> tool pprof -inuse_space http:<span class="comment">//127.0.0.1:8080/debug/pprof/heap</span></span><br><span class="line">    <span class="keyword">go</span> tool pprof -inuse_objects http:<span class="comment">//127.0.0.1:8080/debug/pprof/heap</span></span><br><span class="line"># 查看临时内存分配数据</span><br><span class="line">    <span class="keyword">go</span> tool pprof -alloc_space http:<span class="comment">//127.0.0.1:8080/debug/pprof/heap</span></span><br><span class="line">    <span class="keyword">go</span> tool pprof -alloc_objects http:<span class="comment">//127.0.0.1:8080/debug/pprof/heap</span></span><br></pre></td></tr></table></figure>

<h2 id="七、go-torch和火焰图"><a href="#七、go-torch和火焰图" class="headerlink" title="七、go-torch和火焰图"></a>七、go-torch和火焰图</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 这个下的东西太多了 复制自七米老师的博客</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">火焰图（Flame Graph）是 Bredan Gregg 创建的一种性能分析图表，因为它的样子近似 🔥而得名。上面的 profiling 结果也转换成火焰图，如果对火焰图比较了解可以手动来操作，不过这里我们要介绍一个工具：go-torch。这是 uber 开源的一个工具，可以直接读取 golang profiling 数据，并生成一个火焰图的 svg 文件。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">安装go-torch</span></span><br><span class="line"><span class="comment">   go get -v github.com/uber/go-torch</span></span><br><span class="line"><span class="comment">火焰图 svg 文件可以通过浏览器打开，它对于调用图的最优点是它是动态的：可以通过点击每个方块来 zoom in 分析它上面的内容。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">火焰图的调用顺序从下到上，每个方块代表一个函数，它上面一层表示这个函数会调用哪些函数，方块的大小代表了占用 CPU 使用的长短。火焰图的配色并没有特殊的意义，默认的红、黄配色是为了更像火焰而已。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">go-torch 工具的使用非常简单，没有任何参数的话，它会尝试从http://localhost:8080/debug/pprof/profile获取 profiling 数据。它有三个常用的参数可以调整：</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">-u –url：要访问的 URL，这里只是主机和端口部分</span></span><br><span class="line"><span class="comment">-s –suffix：pprof profile 的路径，默认为 /debug/pprof/profile</span></span><br><span class="line"><span class="comment">–seconds：要执行 profiling 的时间长度，默认为 30s</span></span><br><span class="line"><span class="comment">安装 FlameGraph</span></span><br><span class="line"><span class="comment">要生成火焰图，需要事先安装 FlameGraph工具，这个工具的安装很简单（需要perl环境支持），只要把对应的可执行文件加入到环境变量中即可。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">下载安装perl：https://www.perl.org/get.html</span></span><br><span class="line"><span class="comment">下载FlameGraph：git clone https://github.com/brendangregg/FlameGraph.git</span></span><br><span class="line"><span class="comment">将FlameGraph目录加入到操作系统的环境变量中。</span></span><br><span class="line"><span class="comment">Windows平台的同学，需要把go-torch/render/flamegraph.go文件中的GenerateFlameGraph按如下方式修改，然后在go-torch目录下执行go install即可。</span></span><br><span class="line"><span class="comment">// GenerateFlameGraph runs the flamegraph script to generate a flame graph SVG. func GenerateFlameGraph(graphInput []byte, args ...string) ([]byte, error) &#123;</span></span><br><span class="line"><span class="comment">flameGraph := findInPath(flameGraphScripts)</span></span><br><span class="line"><span class="comment">if flameGraph == &quot;&quot; &#123;</span></span><br><span class="line"><span class="comment">	return nil, errNoPerlScript</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">if runtime.GOOS == &quot;windows&quot; &#123;</span></span><br><span class="line"><span class="comment">	return runScript(&quot;perl&quot;, append([]string&#123;flameGraph&#125;, args...), graphInput)</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">  return runScript(flameGraph, args, graphInput)</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">压测工具wrk</span></span><br><span class="line"><span class="comment">推荐使用https://github.com/wg/wrk 或 https://github.com/adjust/go-wrk</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">使用go-torch</span></span><br><span class="line"><span class="comment">使用wrk进行压测:</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">go-wrk -n 50000 http://127.0.0.1:8080/book/list</span></span><br><span class="line"><span class="comment">在上面压测进行的同时，打开另一个终端执行:</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">go-torch -u http://127.0.0.1:8080 -t 30</span></span><br><span class="line"><span class="comment">30秒之后终端会初夏如下提示：Writing svg to torch.svg</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">然后我们使用浏览器打开torch.svg就能看到如下火焰图了。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line">火焰图的y轴表示cpu调用方法的先后，x轴表示在每个采样调用时间内，方法所占的时间百分比，越宽代表占据cpu时间越多。通过火焰图我们就可以更清楚的找出耗时长的函数调用，然后不断的修正代码，重新采样，不断优化。</span><br><span class="line"></span><br><span class="line">此外还可以借助火焰图分析内存性能数据：</span><br><span class="line"><span class="keyword">go</span>-torch -inuse_space http:<span class="comment">//127.0.0.1:8080/debug/pprof/heap</span></span><br><span class="line"><span class="keyword">go</span>-torch -inuse_objects http:<span class="comment">//127.0.0.1:8080/debug/pprof/heap</span></span><br><span class="line"><span class="keyword">go</span>-torch -alloc_space http:<span class="comment">//127.0.0.1:8080/debug/pprof/heap</span></span><br><span class="line"><span class="keyword">go</span>-torch -alloc_objects http:<span class="comment">//127.0.0.1:8080/debug/pprof/heap</span></span><br></pre></td></tr></table></figure>

<h2 id="八、pprof与性能测试结合"><a href="#八、pprof与性能测试结合" class="headerlink" title="八、pprof与性能测试结合"></a>八、pprof与性能测试结合</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">go</span> test命令有两个参数和 pprof 相关，它们分别指定生成的 CPU 和 Memory profiling 保存的文件：</span><br><span class="line"></span><br><span class="line">-cpuprofile：cpu profiling 数据要保存的文件地址</span><br><span class="line">-memprofile：memory profiling 数据要报文的文件地址</span><br><span class="line">我们还可以选择将pprof与性能测试相结合，比如：</span><br><span class="line"></span><br><span class="line">比如下面执行测试的同时，也会执行 CPU profiling，并把结果保存在 cpu.prof 文件中：</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> test -bench . -cpuprofile=cpu.prof</span><br><span class="line">比如下面执行测试的同时，也会执行 Mem profiling，并把结果保存在 cpu.prof 文件中：</span><br><span class="line"></span><br><span class="line"><span class="keyword">go</span> test -bench . -memprofile=./mem.prof</span><br><span class="line">需要注意的是，Profiling 一般和性能测试一起使用，这个原因在前文也提到过，只有应用在负载高的情况下 Profiling 才有意义。</span><br></pre></td></tr></table></figure>


            </div>

            <!-- Post Comments -->
            
    <!-- 使用 DISQUS_CLICK -->
<div id="disqus-comment">
    <div id="disqus_thread"></div>

<!-- add animation -->
<style>
	.disqus_click_btn {
            line-height: 30px;
            margin: 0;
            min-width: 50px;
            padding: 0 14px;
            display: inline-block;
            font-family: "Roboto", "Helvetica", "Arial", sans-serif;
            font-size: 14px;
            font-weight: 400;
            text-transform: uppercase;
            letter-spacing: 0;
            overflow: hidden;
            will-change: box-shadow;
            transition: box-shadow .2s cubic-bezier(.4, 0, 1, 1), background-color .2s cubic-bezier(.4, 0, .2, 1), color .2s cubic-bezier(.4, 0, .2, 1);
            outline: 0;
            cursor: pointer;
            text-decoration: none;
            text-align: center;
            vertical-align: middle;
            border: 0;
            background: rgba(158, 158, 158, .2);
            box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12);
            color: #fff;
            background-color: #7EC0EE;
            text-shadow: 0
        }
</style>
	
<div class="btn_click_load" id="disqus_bt"> 
    <button class="disqus_click_btn">点击查看评论</button>
</div>

<!--
<script type="text/javascript">
$('.btn_click_load').click(function() {
    /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
    var disqus_shortname = 'http-miccall-tech'; // required: replace example with your forum shortname

    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function() {
      var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
      dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
      (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();

    document.getElementById('disqus_bt').style.display = "none";
});
</script>
-->
<script type="text/javascript">
    var disqus_config = function () {
        this.page.url = 'https://gitee.com/AmeX/amelin-ting.git/2018/06/10/Go%E6%B5%8B%E8%AF%95------%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/';  // Replace PAGE_URL with your page's canonical URL variable
        this.page.identifier = 'https://gitee.com/AmeX/amelin-ting.git/2018/06/10/Go%E6%B5%8B%E8%AF%95------%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/'; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
    };
</script>

<script type="text/javascript">
    $('.btn_click_load').click(function() {  //click to load comments
        (function() { // DON'T EDIT BELOW THIS LINE
            var d = document;
            var s = d.createElement('script');
            s.src = '//http-miccall-tech.disqus.com/embed.js';
            s.setAttribute('data-timestamp', + new Date());
            (d.head || d.body).appendChild(s);
        })();
        $('.btn_click_load').css('display','none');
    });
</script>
</div>
<style>
    #disqus-comment{
        background-color: #eee;
        padding: 2pc;
    }
</style>


        </div>
        <!-- Copyright 版权 start -->
                <div id="copyright">
            <ul>
                <li>&copy;Powered By <a target="_blank" rel="noopener" href="https://hexo.io/zh-cn/" style="border-bottom: none;">hexo</a></li>
                <li>Design: <a target="_blank" rel="noopener" href="http://miccall.tech " style="border-bottom: none;">miccall</a></li>
            </ul>
            
                <span id="busuanzi_container_site_pv">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
			
        </div>
    </div>
</body>



 	
</html>
